#pragma once

#include <occmesh/api/meshdef.h>
#include <occmesh/api/feature.h>

#include <queue>

/**
 * @file Chart.h
 * @author xingyifan
 * @date 2023-08-17 14:40
 *
 * @description: 记录面的状态
 */

class FaceState
{
  private:
    Mesh::FaceHandle m_face;

    std::vector<int> m_setDistances; // 记录到每个特征集的距离
    float m_distance;                // 平均距离

    int m_touch;
    bool m_border;

    // 所属的图表
    size_t m_chart;

  public:
    FaceState(Mesh::FaceHandle face, size_t numSets)
        : m_face(face), m_setDistances(numSets, 0), m_distance(0.0f), m_touch(0), m_border(false), m_chart(SIZE_MAX)
    {
    }

    FaceState() : FaceState(Mesh::FaceHandle(), 0)
    {
    }

    bool border() const
    {
        return m_border;
    }
    bool hasSetDistance(int set) const
    {
        return m_setDistances[set] != 0;
    }
    float distance() const
    {
        return m_distance;
    }
    size_t chart() const
    {
        return m_chart;
    }
    void setChart(size_t chart)
    {
        m_chart = chart;
    }
    bool hasChart() const
    {
        return m_chart != SIZE_MAX;
    }

    void setSetDistance(int set, int distance); // 设置到集合的距离
    void calcDistance();                        // 计算到所有集合距离的平方平均
};

/**
 * @file Chart.h
 * @author xingyifan
 * @date 2023-08-17 14:40
 *
 * @description: 记录图表
 */

class Chart
{
  private:
    static int s_count;

    int m_id;              // 图表 id
    FaceList m_faces;      // 图表包含的面
    VertexList m_vertices; // 图表包含的顶点
    float m_maxDistance;   // 记录到边界的最大距离

  public:
    Chart() : m_id(s_count++), m_maxDistance(0)
    {
    }

    int id() const
    {
        return m_id;
    }
    const FaceList &faces() const
    {
        return m_faces;
    }
    FaceList &faces()
    {
        return m_faces;
    }
    const VertexList &vertices() const
    {
        return m_vertices;
    }
    VertexList &vertices()
    {
        return m_vertices;
    }
    float maxDistance() const
    {
        return m_maxDistance;
    }
    bool cleared() const
    {
        return m_faces.empty();
    }
    bool contains(const Mesh::FaceHandle &fh) const;      // 检查是否包含这个面
    bool add(const Mesh::FaceHandle &fh, float distance); // 添加面和距离
    void merge(const Chart &other);
    void clear();
};

/**
 * @file ChartBuilder.h
 * @author xingyifan
 * @date 2023-08-17 14:41
 *
 * @description: 图表构建器
 */

class ChartBuilder
{
  private:
    // 保存网格和特征集
    Mesh *m_mesh;
    const std::vector<FeatureSet> &m_featureSets;

    // 记录最大距离
    float m_maxDistance;

    // 保存图表
    std::vector<Chart> m_charts;

    // 用来增加边和面的属性
    OpenMesh::EPropHandleT<int> m_chartBoundaries;
    OpenMesh::FPropHandleT<FaceState> m_faceStates;

  public:
    ChartBuilder(Mesh *mesh, const std::vector<FeatureSet> &sets);
    ~ChartBuilder();

    const std::vector<Chart> &Build();
    bool Validate();

  private:
    void initializeDistance(); // 初始化每个面到每个特征集的距离
    void initializeSeeds();    // 初始化图表种子
    void buildCharts();        // 构建图表

    bool removeChartBoundaryEdge(Mesh::EdgeHandle edge);
    bool checkChartBoundaryEdge(Mesh::EdgeHandle edge);
    void mergeCharts(Chart &chartTo, Chart &chartFrom);
};